package com.eu.ebpm.engine.express;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.eu.ebpm.engine.exception.WorkFlowException;
import com.eu.ebpm.engine.express.validator.NumberTypeValidator;
import com.eu.ebpm.engine.express.validator.TypeValidator;

/**
 * 
 * 类名称: ConditionItem
 * 类描述: 
 * @author 王晓华
 * @since 2013-12-23 下午03:22:14
 * @version v1.0
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public class ExpressItem {
	
	private static Logger logger = LoggerFactory.getLogger(ExpressItem.class);

	//表达式:  day > 3 && aply == 'agree' && result == true
	private String express;
	
	private List<Variable> variables = new ArrayList<Variable>();
	
	public ExpressItem(String itemExpress) {
		
		logger.info("[item express] ==> {}", itemExpress);
		
		express = itemExpress.replace("&&", "&");
		
		for(String exp : express.split("&")) {
			variables.add(parseExpressToVariable(exp.trim()));
		}
		
	}

	public String getExpress() {
		return express;
	}

	public void setExpress(String express) {
		this.express = express;
	}

	public List<Variable> getVariables() {
		return variables;
	}

	public void setVariables(List<Variable> variables) {
		this.variables = variables;
	}
	
	/**
	 * 验证matchMap是否符合表达式
	 * 
	 * 第一种：非sizeType类型
	 *  	1、variables任何一个在matchMap找不到对应的值
	 *  	2、matchMap与variables中对应不上，表达式不一致
	 *  
	 *  第二种：sizeType类型 (check1.result == "manager").size() >= 2 && check1.agree
	 *  	1、variables任何一个在matchMap找不到对应的值
	 *  	2、matchMap的匹配个数不符合variables.sizeExpress
	 *  
	 * @param matchMap 传入条件，用map封装的key_value值
	 */
	public boolean isMate(Map<String, Object> matchMap) {
		
		for(Variable expressVariable : this.variables) {
			
			Object value = matchMap.get(expressVariable.getName());
			
			if(value == null) {
				return false;
			}
			
			TypeValidator<?> validator = expressVariable.getType().getParser();
			
			// 1、非sizeType类型
			if(!expressVariable.getSizeType()) {
				
				if(!validator.checkVariable(expressVariable, value)) {
					return false;
				}
				
			} 
			
			// 2、sizeType类型 (check1.result == "manager").size() >= 2 && check1.agree
			else {
				
				int successCount = 0;
				
				for(String key : matchMap.keySet()) {
					if(key.contains(expressVariable.getName()) && !key.equals(expressVariable.getName())) {
						if(validator.checkVariable(expressVariable, matchMap.get(key))) {
							successCount ++;
						}
					}
				}
				
				if(!NumberTypeValidator.check(expressVariable.getSizeExpress(), expressVariable.getSizeValue(), new BigDecimal(successCount))) {
					return false;
				}
				
			}
			
		}
		
		return true;
	}
	
	public static Variable<?> parseExpressToVariable(String express) {
		
		Variable<?> v = null;
		
		boolean isSizeExpress = false;
		
		String sizeExpress = null;
		
		Matcher m = null;
		
		// 1、判断是否匹配个数表达式
		if(express.contains(").size()") || express.contains(").length") || express.contains(").size") || express.contains(").length()")) {
			isSizeExpress = true;
			sizeExpress = express.substring(express.indexOf(")."), express.length());
			express = express.substring(1, express.indexOf(")."));
		}
		
		// 2.1、匹配数字【day >= 3】
		if(express.matches("[a-zA-Z_.0-9]+\\s*[><=!]{1,2}\\s*\\-*[0-9.]+")) {
			v = new Variable<BigDecimal>();
			v.setType(VariableType.NUMBER);
			m = Pattern.compile("[a-zA-Z_.0-9]+").matcher(express);
			if(m.find()) v.setName(m.group().trim());
			m = Pattern.compile("[><=!]{1,2}").matcher(express);
			if(m.find()) v.setExpress(m.group().trim());
			m = Pattern.compile("\\-*[0-9.]+").matcher(express);
			while(m.find()) v.setValue(new BigDecimal(m.group().trim()));
		} 
		
		// 2.2、匹配字符串【apply = 'agree'】
		else if(express.matches("[a-zA-Z_.0-9]+\\s*[\\!=]{1,2}\\s*[\\'\\\"]{1}\\w+[\\'\\\"]{1}")) {
			v = new Variable<String>();
			v.setType(VariableType.STRING);
			m = Pattern.compile("[\\!=]{1,2}").matcher(express);
			m.find();
			int start = m.start();
			v.setName(express.substring(0, start).trim());
			v.setExpress(m.group());
			String value = express.substring(express.indexOf(v.getExpress()) + v.getExpress().length(), express.length()).trim();
			v.setValue(value.substring(1, value.length() -1));
		} 
		
		// 2.3、匹配boolean【result】
		else if(express.matches("\\!?[a-zA-Z_.0-9]+")) {
			v = new Variable<Boolean>();
			v.setType(VariableType.BOOLEAN);
			if(express.indexOf("!") == 0) {
				v.setName(express.substring(1, express.length()));
				v.setValue(false);
			} else {
				v.setName(express);
				v.setValue(true);
			}
		} else {
			throw new WorkFlowException("表达式有误" + express);
		}
		
		// 3、匹配个数表达式处理
		if(isSizeExpress) {
			
			v.setSizeType(true);
			
			m = Pattern.compile("[><=!]{1,2}").matcher(sizeExpress);
			if(m.find()) {
				v.setSizeExpress(m.group().trim());
			}
			
			m = Pattern.compile("\\-*[0-9]+").matcher(sizeExpress);
			while(m.find()) {
				v.setSizeValue(new BigDecimal(m.group().trim()));
			}
			
		}
		
		return v;
	}

	@Override
	public String toString() {
		return "ExpressItem [express=" + express + ", variables=" + variables + "]";
	}
	
}
